﻿using System;
using System.Collections.Concurrent;

namespace Taxhui.Utils.Network.Tcp.Pooling
{
    /// <summary>
    /// 对象池
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class ObjectPool<T> : IDisposable
    {
        private readonly ConcurrentStack<T> _stack; //对象栈
        private readonly object _opLock = new object();
        private bool _isDisposed; //已销毁标志
        #region 构造函数
        public ObjectPool()
        {
            _stack = new ConcurrentStack<T>();
        }
        #endregion
        //创建对象
        protected abstract T Create();
        //对象池中对象的数量
        public int Count
        {
            get
            {
                return _stack.Count;
            }
        }
        #region 增加新对象
        public void Add(T item)
        {
            if (item == null)
                throw new ArgumentNullException("item");
            _stack.Push(item);
        }
        #endregion
        #region 取出对象
        public T Take()
        {            
            //如果出栈失败就创建一个新对象返回
            if (_stack.TryPop(out T item))
                return item;
            return Create();
        }
        #endregion
        //已销毁标志
        public bool IsDisposed
        {
            get
            {
                lock (_opLock)
                {
                    return _isDisposed;
                }
            }
        }
        #region 析构函数
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            lock (_opLock)
            {
                if (_isDisposed)
                    return;

                if (disposing)
                {
                    //取出池中的所有对象并干掉
                    for (int i = 0; i < this.Count; i++)
                    {
                        if (this.Take() is IDisposable item)
                            item.Dispose();
                    }

                }
                _isDisposed = true;
            }
        }
        #endregion
    }
}
